Load Data

# File generated in /perturbation_16s/analysis/analysis_summer2019/generate_phyloseq.rmd
psSubj <- readRDS("../../data/16S/phyloseq/perturb_physeq_participants_decontam_15Jul19.rds")
psSubj
phyloseq-class experiment-level object
otu_table()   OTU Table:         [ 2425 taxa and 4402 samples ]
sample_data() Sample Data:       [ 4402 samples by 40 sample variables ]
tax_table()   Taxonomy Table:    [ 2425 taxa by 12 taxonomic ranks ]
phy_tree()    Phylogenetic Tree: [ 2425 tips and 2424 internal nodes ]
# otu_table()   OTU Table:         [ 2425 taxa and 4402 samples ]
# sample_data() Sample Data:       [ 4402 samples by 40 sample variables ]
SMP <- data.frame(sample_data(psSubj))
SUBJ <- SMP %>% select(Subject, Age:BirthYear) %>% distinct()
load("output/pairwise_dist_to_baseline_subj_16S.rda")
load("output/fpca_res.rda")
ls()
 [1] "abx_intv_cols"         "bray_to_baseline"      "bray_to_baseline_fltr" "bray.df"               "brayD.ihs"            
 [6] "cc_intv_cols"          "curdir"                "datadir"               "diet_intv_cols"        "fpca.bray.abx"        
[11] "fpca.bray.cc"          "fpca.bray.diet"        "fpca.bray.diet30"      "intv_cols"             "jacc_to_baseline"     
[16] "jacc.df"               "jaccardD"              "pAbx"                  "pAbxLab"               "pBray"                
[21] "pDiet"                 "pDietLab"              "psSubj"                "SMP"                   "SUBJ"                 
[26] "theme_subplot"         "uniFrac_to_baseline"   "uniFrac.df"            "uniFracD.lst"         

Functional PCA

fit_fdapca <- function(
  df, time_column, value_column, replicate_column,
  feat_column = NULL, feat = NULL,
  cluster = FALSE, cmethod = "EMCluster", K = 2, filter = TRUE,
  thresh = 0, num_nonzero = 10, clust_min_num_replicate = 10,
  fpca_optns = NULL, fclust_optns = NULL)
{
  if(!is.null(feat) & !is.null(feat_column)) {
    df <- df %>% 
      filter_at(.vars = feat_column, any_vars((.) == feat))
  }
  y_lst <- plyr::dlply(df, replicate_column, function(x) x[[value_column]])
  t_lst <- plyr::dlply(df, replicate_column, function(x) x[[time_column]])
  if (filter){
    idx <- sapply(y_lst, function(y){sum(abs(y) > thresh) >= num_nonzero})
    y_lst <- y_lst[idx]
    t_lst <- t_lst[idx]
  }  
  if(length(y_lst) == 0) return(NULL)
  feat_res <- NULL
  if(cluster & (length(y_lst) >= clust_min_num_replicate)) {
    feat_res <- try(fdapace::FClust(
      y_lst, t_lst, k = K, optnsFPCA = fpca_optns, optnsCS = fclust_optns))
  } else {
    if(is.null(fpca_optns)) {
      fpca_optns <- list()
    } 
    if (length(y_lst) < clust_min_num_replicate) {
      fpca_optns$dataType <- 'Sparse'
    }
    feat_res <- fdapace::FPCA(y_lst, t_lst, optns = fpca_optns)
    if(cluster){
      feat_res <- list("cluster" = rep(1, length(y_lst)), 
                       "fpca" = feat_res, "clusterObj" = NULL)
    }
  }
  feat_res
}
fitted_values_fpca <- function(obj, derOptns = list(p = 0)) 
{
  selectedK <- NULL; clust_df <- NULL
  if("cluster" %in% names(obj)){
    clust_df <- data.frame(
      "Replicate_ID" = names(obj$fpca$inputData$Ly),
      "Cluster" =  as.character(obj[["cluster"]]),
      stringsAsFactors = FALSE)
    obj <- obj[["fpca"]]
  }
  if(derOptns$p > 0) {
    selectedK <- fdapace::SelectK(obj)$K
    if(!is.finite(selectedK)) selectedK <- ncol(obj$xiEst)
  }  
  fit <- fdapace:::fitted.FPCA(obj, K = selectedK, derOptns = derOptns)
  rownames(fit) <- names(obj$inputData$Ly)
  colnames(fit) <- obj$workGrid
  fit <- reshape2::melt(fit, varnames = c("Replicate_ID", "time")) %>%
    mutate(Replicate_ID = as.character(Replicate_ID))
  if(!is.null(clust_df)){
    fit <- suppressMessages(fit  %>% left_join(clust_df))
  }
  return(fit)
}
fit_dist_to_baseline <- function(
  dist_to_baseline, time_column="RelDay", 
  value_column = "dist_to_baseline", replicate_column = "Subject") 
{
  nGrid <- length(
    seq(min(dist_to_baseline[[time_column]]),
        max(dist_to_baseline[[time_column]])))
  fpca_res <- fit_fdapca(
    dist_to_baseline, time_column, value_column, replicate_column,
    cluster = FALSE, filter = FALSE, fpca_optns = list(nRegGrid = nGrid))
  
  fitted_mean <- data.frame(time = fpca_res$workGrid, value = fpca_res$mu)
  fitted_response <- fitted_values_fpca(fpca_res) %>%
    mutate(Subject = Replicate_ID) %>%
    left_join(
      fitted_values_fpca(fpca_res, derOptns = list(p = 1)) %>%
        mutate(Subject = Replicate_ID) %>%
        rename("deriv" = value)
    )
  return(list(res = fpca_res, mean = fitted_mean, fitted = fitted_response))
}
# this is because some subjects have multiple samples take the same day
bray_to_baseline_fltr <- bray_to_baseline %>% 
  group_by(perturbation, Subject, Group, Interval, RelDay) %>%
  summarise(n = n(), dist_to_baseline = mean(dist_to_baseline)) %>%
  ungroup()
bray_to_baseline_fltr %>% filter(n > 1)

Antibiotics

bray_to_baseline_fltr %>% 
  filter(perturbation == "Abx") %>%
  filter(RelDay >= -50, RelDay <= 60) %>%
  mutate(Interval = factor(Interval, level = names(abx_intv_cols))) %>%
  ggplot(
    aes(x = RelDay, y = dist_to_baseline, 
        group = Subject, color = Interval)) +
  geom_line(aes(group = Subject), alpha = 0.7, lwd = 0.5) + 
  geom_point(alpha = 0.5, size = 1.2) + 
  scale_color_manual(values = abx_intv_cols) + 
  theme(legend.position = "bottom") + 
  guides(colour = guide_legend(override.aes = list(size=3))) +
  xlab("Days from initial antibiotic dose") +
  ylab("Bray-Curtis distance to 7 pre-antibiotic samples") 

fpca.bray.abx <- fit_dist_to_baseline(
  bray_to_baseline_fltr %>% filter(perturbation == "Abx", RelDay >= -50, RelDay <= 60))

save(list = c("fpca.bray.abx"), file = "output/fpca_res.rda")
(pAbx <- bray_to_baseline_fltr %>% 
  filter(perturbation == "Abx", RelDay >= -50, RelDay <= 60) %>%
ggplot(aes(x = RelDay, y = dist_to_baseline)) +
  geom_line(
    data = fpca.bray.abx[["fitted"]],
    aes(group = Subject, x = time, y = value),
    alpha = 0.3, size = 0.7, color = "grey30") +
  geom_vline(xintercept = 0, lwd = 1, color = "orange") +
  geom_vline(xintercept = 4, lwd = 1, color = "orange") +
  geom_point(aes(color = Interval), size = 1.5, alpha = 0.7) +
  geom_line(
    data = fpca.bray.abx[["mean"]], aes(x = time, y = value),
    color = "navy", size = 2) +
  scale_color_manual(values = abx_intv_cols, name = "Interval") +
  scale_x_continuous(
    name = "Days from initial antibiotic dose",
    limits = c(NA, NA), breaks = seq(-50, 60, 10)) +
  scale_y_continuous(
    name = "Bray-Curtis distance to baseline", 
    limits = c(0.1, 0.85), breaks = seq(0.1, 0.80, 0.1)) +
  theme(text = element_text(size = 20)))

fpca.bray.abx[["fitted"]] <- fpca.bray.abx[["fitted"]] %>%
  mutate(
    Interval = ifelse(fpca.bray.abx[["fitted"]]$time < 0 , "PreAbx",
               ifelse(fpca.bray.abx[["fitted"]]$time >= 0 & fpca.bray.abx[["fitted"]]$time <= 4, "MidAbx",
                      "PostAbx")))
(pAbxDeriv <-  fpca.bray.abx[["fitted"]] %>%
  ggplot(aes(x = RelDay)) +
  geom_line(
    aes(group = Subject, x = time, y = deriv, color = Interval),
    alpha = 0.5, size = 0.7) +
  geom_vline(xintercept = 0, lwd = 1, color = "orange") +
  geom_vline(xintercept = 4, lwd = 1, color = "orange") +
  scale_color_manual(values = abx_intv_cols, name = "Interval") +
  scale_x_continuous(name = "",
    limits = c(NA, NA), breaks = seq(-50, 60, 10)) +
  ylab("Derivative"))

(pAbxLab <- bray_to_baseline_fltr %>% 
  filter(perturbation == "Abx", RelDay >= -50, RelDay <= 60) %>%
ggplot(aes(x = RelDay, y = dist_to_baseline)) +
  geom_line(
    data = fpca.bray.abx[["fitted"]],
    aes(group = Subject, x = time, y = value),
    alpha = 0.3, size = 0.7 ) +
  geom_vline(xintercept = 0, lwd = 1, color = "orange") +
  geom_vline(xintercept = 4, lwd = 1, color = "orange") +
  geom_text(
      aes(label = Subject, color = Interval), size = 4, alpha = 0.7) +
  geom_line(
    data = fpca.bray.abx[["mean"]], aes(x = time, y = value),
    color = "navy", size = 2) +
  scale_color_manual(values = abx_intv_cols, name = "Interval") +
  scale_x_continuous(
    name = "Days from initial antibiotic dose",
    limits = c(NA, NA), breaks = seq(-50, 60, 10)) +
  scale_y_continuous(
    name = "Bray-Curtis distance to baseline", 
    limits = c(0.1, 0.85), breaks = seq(0.1, 0.80, 0.1)) +
  theme(text = element_text(size = 20)))

  # geom_point(
  #     data = abx_bray %>% filter(RelDay > StabTime),
  #     color = "orange", size = 2.5) +
vp = grid::viewport(width = 0.3, height = 0.32, x = 0.07, y =0.95, just = c("left", "top"))
print(pAbx)
print(pAbxDeriv + theme_bw(base_size = 10) + theme_subplot, vp = vp)

Diet

bray_to_baseline_fltr %>% 
  filter(perturbation == "Diet", RelDay >= -30, RelDay <= 30) %>%
  mutate(Interval = factor(Interval, level = names(diet_intv_cols))) %>%
  ggplot(
    aes(x = RelDay, y = dist_to_baseline, 
        group = Subject, color = Interval)) +
  geom_line(aes(group = Subject), alpha = 0.7, lwd = 0.5) + 
  geom_point(alpha = 0.5, size = 1.2) + 
  scale_color_manual(values = diet_intv_cols) + 
  theme(legend.position = "bottom") + 
  guides(colour = guide_legend(override.aes = list(size=3))) +
  xlab("Days from diet initiation") +
  ylab("Bray-Curtis distance to 7 pre-diet samples") 

fpca.bray.diet30 <- fit_dist_to_baseline(
  bray_to_baseline_fltr %>% filter(perturbation == "Diet", RelDay >= -30, RelDay <= 30))

save(list = c("fpca.bray.abx", "fpca.bray.diet", "fpca.bray.diet30"), file = "output/fpca_res.rda")
(pDiet <- bray_to_baseline_fltr %>% 
  filter(perturbation == "Diet", RelDay >= -30, RelDay <= 30) %>%
ggplot(aes(x = RelDay, y = dist_to_baseline)) +
  geom_line(
    data = fpca.bray.diet30[["fitted"]],
    aes(group = Subject, x = time, y = value),
    alpha = 0.3, size = 0.7, color = "grey30") +
  geom_vline(xintercept = 0, lwd = 1, color = "orange") +
  geom_vline(xintercept = 4, lwd = 1, color = "orange") +
  geom_point(aes(color = Interval), size = 1.5, alpha = 0.7) +
  geom_line(
    data = fpca.bray.diet30[["mean"]], aes(x = time, y = value),
    color = "navy", size = 2) +
  scale_color_manual(values = diet_intv_cols, name = "Interval") +
  scale_x_continuous(
    name = "Days from initial antibiotic dose",
    limits = c(NA, NA), breaks = seq(-50, 60, 10)) +
  scale_y_continuous(
    name = "Bray-Curtis distance to baseline", 
    limits = c(NA, NA), breaks = seq(0.1, 0.80, 0.1)) +
  theme(text = element_text(size = 20))) 

fpca.bray.diet30[["fitted"]] <- fpca.bray.diet30[["fitted"]] %>%
  mutate(
    Interval = ifelse(fpca.bray.diet30[["fitted"]]$time < 0 , "PreDiet",
               ifelse(fpca.bray.diet30[["fitted"]]$time >= 0 & fpca.bray.diet30[["fitted"]]$time <= 4, "MidDiet",
                      "PostDiet")))
(pDietDeriv <-  fpca.bray.diet30[["fitted"]] %>%
  ggplot(aes(x = RelDay)) +
  geom_line(
    aes(group = Subject, x = time, y = deriv, color = Interval),
    alpha = 0.5, size = 0.7) +
  geom_vline(xintercept = 0, lwd = 1, color = "orange") +
  geom_vline(xintercept = 4, lwd = 1, color = "orange") +
  scale_color_manual(values = diet_intv_cols, name = "Interval") +
  scale_x_continuous(name = "",
    limits = c(NA, NA), breaks = seq(-50, 60, 10)) +
  ylab("Derivative"))

(pDietLab <- bray_to_baseline_fltr %>% 
  filter(perturbation == "Diet", RelDay >= -50, RelDay <= 60) %>%
ggplot(aes(x = RelDay, y = dist_to_baseline)) +
  geom_line(
    data = fpca.bray.diet[["fitted"]],
    aes(group = Subject, x = time, y = value),
    alpha = 0.3, size = 0.7 ) +
  geom_vline(xintercept = 0, lwd = 1, color = "orange") +
  geom_vline(xintercept = 4, lwd = 1, color = "orange") +
  geom_text(
      aes(label = Subject, color = Interval), size = 4, alpha = 0.7) +
  geom_line(
    data = fpca.bray.diet[["mean"]], aes(x = time, y = value),
    color = "navy", size = 2) +
  scale_color_manual(values = diet_intv_cols, name = "Interval") +
  scale_x_continuous(
    name = "Days from initial antibiotic dose",
    limits = c(NA, NA), breaks = seq(-50, 60, 10)) +
  scale_y_continuous(
    name = "Bray-Curtis distance to baseline", 
    limits = c(0.1, 0.85), breaks = seq(0.1, 0.80, 0.1)) +
  theme(text = element_text(size = 20)))

vp = grid::viewport(width = 0.3, height = 0.32, x = 0.07, y =0.95, just = c("left", "top"))
print(pDiet)
print(pDietDeriv + theme_bw(base_size = 10) + theme_subplot, vp = vp)

Colon cleanout

bray_to_baseline_fltr %>% 
  filter(perturbation == "CC", RelDay >= -50, RelDay <= 50) %>%
  mutate(Interval = factor(Interval, level = names(cc_intv_cols))) %>%
  ggplot(
    aes(x = RelDay, y = dist_to_baseline, 
        group = Subject, color = Interval)) +
  geom_line(aes(group = Subject), alpha = 0.7, lwd = 0.5) + 
  geom_point(alpha = 0.5, size = 1.2) + 
  scale_color_manual(values = cc_intv_cols) + 
  theme(legend.position = "bottom") + 
  guides(colour = guide_legend(override.aes = list(size=3))) +
  xlab("Days from diet initiation") +
  ylab("Bray-Curtis distance to 7 pre-diet samples") 

fpca.bray.cc30 <- fit_dist_to_baseline(
  bray_to_baseline_fltr %>% 
    filter(perturbation == "CC", RelDay >= -30, RelDay <= 30) %>%
    arrange(Subject, RelDay))
Joining, by = c("Replicate_ID", "time", "Subject")
save(list = c("fpca.bray.abx", "fpca.bray.diet","fpca.bray.diet30", 
              "fpca.bray.cc", "fpca.bray.cc30"), 
     file = "output/fpca_res.rda")
(pCC <- bray_to_baseline_fltr %>% 
  filter(perturbation == "CC", RelDay >= -30, RelDay <= 30) %>%
ggplot(aes(x = RelDay, y = dist_to_baseline)) +
  geom_line(
    data = fpca.bray.cc30[["fitted"]],
    aes(group = Subject, x = time, y = value),
    alpha = 0.3, size = 0.7, color = "grey30") +
  geom_vline(xintercept = 0, lwd = 1, color = "orange") +
  geom_vline(xintercept = 4, lwd = 1, color = "orange") +
  geom_point(aes(color = Interval), size = 1.5, alpha = 0.7) +
  geom_line(
    data = fpca.bray.cc30[["mean"]], aes(x = time, y = value),
    color = "navy", size = 2) +
  scale_color_manual(values = cc_intv_cols, name = "Interval") +
  scale_x_continuous(
    name = "Days from initial antibiotic dose",
    limits = c(NA, NA), breaks = seq(-50, 60, 10)) +
  scale_y_continuous(
    name = "Bray-Curtis distance to baseline", 
    limits = c(NA, NA), breaks = seq(0.1, 0.80, 0.1)) +
  theme(text = element_text(size = 20))) 

fpca.bray.cc30[["fitted"]] <- fpca.bray.cc30[["fitted"]] %>%
  mutate(Interval = ifelse(fpca.bray.cc30[["fitted"]]$time < 0 , "PreCC","PostCC"))
(pCCDeriv <-  fpca.bray.cc30[["fitted"]] %>%
  ggplot(aes(x = RelDay)) +
  geom_line(
    aes(group = Subject, x = time, y = deriv, color = Interval),
    alpha = 0.5, size = 0.7) +
  geom_vline(xintercept = 0, lwd = 1, color = "orange") +
  geom_vline(xintercept = 4, lwd = 1, color = "orange") +
  scale_color_manual(values = cc_intv_cols, name = "Interval") +
  scale_x_continuous(name = "",
    limits = c(NA, NA), breaks = seq(-50, 60, 10)) +
  ylab("Derivative"))

(pCCLab <- bray_to_baseline_fltr %>% 
  filter(perturbation == "CC", RelDay >= -50, RelDay <= 50) %>%
ggplot(aes(x = RelDay, y = dist_to_baseline)) +
  geom_line(
    data = fpca.bray.cc[["fitted"]],
    aes(group = Subject, x = time, y = value),
    alpha = 0.3, size = 0.7 ) +
  geom_vline(xintercept = 0, lwd = 1, color = "orange") +
  geom_vline(xintercept = 4, lwd = 1, color = "orange") +
  geom_text(
      aes(label = Subject, color = Interval), size = 4, alpha = 0.7) +
  geom_line(
    data = fpca.bray.cc[["mean"]], aes(x = time, y = value),
    color = "navy", size = 2) +
  scale_color_manual(values = cc_intv_cols, name = "Interval") +
  scale_x_continuous(
    name = "Days from initial antibiotic dose",
    limits = c(NA, NA), breaks = seq(-50, 60, 10)) +
  scale_y_continuous(
    name = "Bray-Curtis distance to baseline", 
    limits = c(0.1, 0.85), breaks = seq(0.1, 0.80, 0.1)) +
  theme(text = element_text(size = 20)))

vp = grid::viewport(width = 0.3, height = 0.32, x = 0.07, y =0.95, just = c("left", "top"))
print(pCC)
print(pCCDeriv + theme_bw(base_size = 10) + theme_subplot, vp = vp)

sessionInfo()
R version 3.5.1 (2018-07-02)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: CentOS Linux 7 (Core)

Matrix products: default
BLAS/LAPACK: /share/software/user/open/openblas/0.2.19/lib/libopenblasp-r0.2.19.so

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8    LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C             LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] fdapace_0.4.1        forcats_0.4.0        stringr_1.4.0        dplyr_0.8.3          purrr_0.3.2          readr_1.3.1         
 [7] tidyr_0.8.3          tibble_2.1.3         ggplot2_3.2.0        tidyverse_1.2.1.9000 RColorBrewer_1.1-2   phyloseq_1.26.1     

loaded via a namespace (and not attached):
 [1] nlme_3.1-140        fs_1.3.1            lubridate_1.7.4     httr_1.4.0          numDeriv_2016.8-1.1 tools_3.5.1        
 [7] backports_1.1.4     utf8_1.1.4          R6_2.4.0            vegan_2.5-5         rpart_4.1-15        Hmisc_4.2-0        
[13] DBI_1.0.0           lazyeval_0.2.2      BiocGenerics_0.28.0 mgcv_1.8-28         colorspace_1.4-1    permute_0.9-5      
[19] ade4_1.7-13         nnet_7.3-12         withr_2.1.2         tidyselect_0.2.5    gridExtra_2.3       compiler_3.5.1     
[25] cli_1.1.0           rvest_0.3.4         Biobase_2.42.0      htmlTable_1.13.1    xml2_1.2.0          labeling_0.3       
[31] scales_1.0.0        checkmate_1.9.4     digest_0.6.20       foreign_0.8-71      rmarkdown_1.14      XVector_0.22.0     
[37] htmltools_0.3.6     base64enc_0.1-3     pkgconfig_2.0.2     dbplyr_1.4.2        htmlwidgets_1.3     rlang_0.4.0        
[43] readxl_1.3.1        rstudioapi_0.10     generics_0.0.2      jsonlite_1.6        acepack_1.4.1       magrittr_1.5       
[49] Formula_1.2-3       biomformat_1.10.1   Matrix_1.2-17       fansi_0.4.0         Rcpp_1.0.1          munsell_0.5.0      
[55] S4Vectors_0.20.1    Rhdf5lib_1.4.3      ape_5.3             stringi_1.4.3       yaml_2.2.0          MASS_7.3-51.4      
[61] zlibbioc_1.28.0     rhdf5_2.26.2        plyr_1.8.4          grid_3.5.1          parallel_3.5.1      crayon_1.3.4       
[67] lattice_0.20-38     Biostrings_2.50.2   haven_2.1.1         splines_3.5.1       multtest_2.38.0     hms_0.5.0          
[73] zeallot_0.1.0       knitr_1.23          pillar_1.4.2        igraph_1.2.4.1      reshape2_1.4.3      codetools_0.2-16   
[79] stats4_3.5.1        reprex_0.3.0        glue_1.3.1          evaluate_0.14       latticeExtra_0.6-28 data.table_1.12.2  
[85] modelr_0.1.4        vctrs_0.2.0         foreach_1.4.4       cellranger_1.1.0    gtable_0.3.0        assertthat_0.2.1   
[91] xfun_0.8            broom_0.5.2         pracma_2.2.5        survival_2.44-1.1   iterators_1.0.10    IRanges_2.16.0     
[97] cluster_2.1.0      
LS0tCnRpdGxlOiAiRnVuY3Rpb25hbCBQQ0EiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmxpYnJhcnkoInBoeWxvc2VxIikKbGlicmFyeSgiUkNvbG9yQnJld2VyIikKbGlicmFyeSgidGlkeXZlcnNlIikKbGlicmFyeSgiZmRhcGFjZSIpCgpkYXRhZGlyIDwtICIuLi8uLi9kYXRhLyIKY3VyZGlyIDwtIGdldHdkKCkKdGhlbWVfc2V0KHRoZW1lX2J3KCkpCnRoZW1lX3VwZGF0ZSh0ZXh0ID0gZWxlbWVudF90ZXh0KDIwKSkKCnRoZW1lX3N1YnBsb3QgPC0gdGhlbWUoCiAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsY29sb3VyID0gTkEpLAogICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsY29sb3VyID0gTkEpCiAgICApCgphYnhfaW50dl9jb2xzIDwtIGMoIlByZUFieCIgPSAiZ3JleTYwIiwgIk1pZEFieCIgPSAiI0U0MUExQyIsIAogICAgICAgICAgICAgICAgICAgIlBvc3RBYngiID0gIiMwMEJGQzQiLCAiVW5wQWJ4IiA9ICJQdXJwbGUiKQpkaWV0X2ludHZfY29scyA8LSBjKCJQcmVEaWV0IiA9ICJncmV5NjAiLCAiTWlkRGlldCIgPSAiI0ZEOEQzQyIsIAogICAgICAgICAgICAgICAgICAgICJQb3N0RGlldCIgPSAiIzREQUY0QSIpCmNjX2ludHZfY29scyA8LSBjKCJQcmVDQyIgPSAiZ3JleTYwIiwgIlBvc3RDQyIgPSAiIzdBMDE3NyIpICMiI0FFMDE3RSIpCgppbnR2X2NvbHMgPC0gYyhhYnhfaW50dl9jb2xzLCBkaWV0X2ludHZfY29scywgY2NfaW50dl9jb2xzLCAiTm9JbnRlcnYiID0gImdyZXk2MCIpCmBgYAoKCgojIExvYWQgRGF0YQoKYGBge3J9CiMgRmlsZSBnZW5lcmF0ZWQgaW4gL3BlcnR1cmJhdGlvbl8xNnMvYW5hbHlzaXMvYW5hbHlzaXNfc3VtbWVyMjAxOS9nZW5lcmF0ZV9waHlsb3NlcS5ybWQKcHNTdWJqIDwtIHJlYWRSRFMoIi4uLy4uL2RhdGEvMTZTL3BoeWxvc2VxL3BlcnR1cmJfcGh5c2VxX3BhcnRpY2lwYW50c19kZWNvbnRhbV8xNUp1bDE5LnJkcyIpCnBzU3ViagojIG90dV90YWJsZSgpICAgT1RVIFRhYmxlOiAgICAgICAgIFsgMjQyNSB0YXhhIGFuZCA0NDAyIHNhbXBsZXMgXQojIHNhbXBsZV9kYXRhKCkgU2FtcGxlIERhdGE6ICAgICAgIFsgNDQwMiBzYW1wbGVzIGJ5IDQwIHNhbXBsZSB2YXJpYWJsZXMgXQpTTVAgPC0gZGF0YS5mcmFtZShzYW1wbGVfZGF0YShwc1N1YmopKQpTVUJKIDwtIFNNUCAlPiUgc2VsZWN0KFN1YmplY3QsIEFnZTpCaXJ0aFllYXIpICU+JSBkaXN0aW5jdCgpCmBgYAoKCmBgYHtyfQpsb2FkKCJvdXRwdXQvcGFpcndpc2VfZGlzdF90b19iYXNlbGluZV9zdWJqXzE2Uy5yZGEiKQpsb2FkKCJvdXRwdXQvZnBjYV9yZXMucmRhIikKbHMoKQpgYGAKCgojIEZ1bmN0aW9uYWwgUENBIAoKCmBgYHtyfQpmaXRfZmRhcGNhIDwtIGZ1bmN0aW9uKAogIGRmLCB0aW1lX2NvbHVtbiwgdmFsdWVfY29sdW1uLCByZXBsaWNhdGVfY29sdW1uLAogIGZlYXRfY29sdW1uID0gTlVMTCwgZmVhdCA9IE5VTEwsCiAgY2x1c3RlciA9IEZBTFNFLCBjbWV0aG9kID0gIkVNQ2x1c3RlciIsIEsgPSAyLCBmaWx0ZXIgPSBUUlVFLAogIHRocmVzaCA9IDAsIG51bV9ub256ZXJvID0gMTAsIGNsdXN0X21pbl9udW1fcmVwbGljYXRlID0gMTAsCiAgZnBjYV9vcHRucyA9IE5VTEwsIGZjbHVzdF9vcHRucyA9IE5VTEwpCnsKICBpZighaXMubnVsbChmZWF0KSAmICFpcy5udWxsKGZlYXRfY29sdW1uKSkgewogICAgZGYgPC0gZGYgJT4lIAogICAgICBmaWx0ZXJfYXQoLnZhcnMgPSBmZWF0X2NvbHVtbiwgYW55X3ZhcnMoKC4pID09IGZlYXQpKQogIH0KICB5X2xzdCA8LSBwbHlyOjpkbHBseShkZiwgcmVwbGljYXRlX2NvbHVtbiwgZnVuY3Rpb24oeCkgeFtbdmFsdWVfY29sdW1uXV0pCiAgdF9sc3QgPC0gcGx5cjo6ZGxwbHkoZGYsIHJlcGxpY2F0ZV9jb2x1bW4sIGZ1bmN0aW9uKHgpIHhbW3RpbWVfY29sdW1uXV0pCiAgaWYgKGZpbHRlcil7CiAgICBpZHggPC0gc2FwcGx5KHlfbHN0LCBmdW5jdGlvbih5KXtzdW0oYWJzKHkpID4gdGhyZXNoKSA+PSBudW1fbm9uemVyb30pCiAgICB5X2xzdCA8LSB5X2xzdFtpZHhdCiAgICB0X2xzdCA8LSB0X2xzdFtpZHhdCiAgfSAgCiAgaWYobGVuZ3RoKHlfbHN0KSA9PSAwKSByZXR1cm4oTlVMTCkKICBmZWF0X3JlcyA8LSBOVUxMCiAgaWYoY2x1c3RlciAmIChsZW5ndGgoeV9sc3QpID49IGNsdXN0X21pbl9udW1fcmVwbGljYXRlKSkgewogICAgZmVhdF9yZXMgPC0gdHJ5KGZkYXBhY2U6OkZDbHVzdCgKICAgICAgeV9sc3QsIHRfbHN0LCBrID0gSywgb3B0bnNGUENBID0gZnBjYV9vcHRucywgb3B0bnNDUyA9IGZjbHVzdF9vcHRucykpCiAgfSBlbHNlIHsKICAgIGlmKGlzLm51bGwoZnBjYV9vcHRucykpIHsKICAgICAgZnBjYV9vcHRucyA8LSBsaXN0KCkKICAgIH0gCiAgICBpZiAobGVuZ3RoKHlfbHN0KSA8IGNsdXN0X21pbl9udW1fcmVwbGljYXRlKSB7CiAgICAgIGZwY2Ffb3B0bnMkZGF0YVR5cGUgPC0gJ1NwYXJzZScKICAgIH0KICAgIGZlYXRfcmVzIDwtIGZkYXBhY2U6OkZQQ0EoeV9sc3QsIHRfbHN0LCBvcHRucyA9IGZwY2Ffb3B0bnMpCiAgICBpZihjbHVzdGVyKXsKICAgICAgZmVhdF9yZXMgPC0gbGlzdCgiY2x1c3RlciIgPSByZXAoMSwgbGVuZ3RoKHlfbHN0KSksIAogICAgICAgICAgICAgICAgICAgICAgICJmcGNhIiA9IGZlYXRfcmVzLCAiY2x1c3Rlck9iaiIgPSBOVUxMKQogICAgfQogIH0KICBmZWF0X3Jlcwp9CgpmaXR0ZWRfdmFsdWVzX2ZwY2EgPC0gZnVuY3Rpb24ob2JqLCBkZXJPcHRucyA9IGxpc3QocCA9IDApKSAKewogIHNlbGVjdGVkSyA8LSBOVUxMOyBjbHVzdF9kZiA8LSBOVUxMCiAgaWYoImNsdXN0ZXIiICVpbiUgbmFtZXMob2JqKSl7CiAgICBjbHVzdF9kZiA8LSBkYXRhLmZyYW1lKAogICAgICAiUmVwbGljYXRlX0lEIiA9IG5hbWVzKG9iaiRmcGNhJGlucHV0RGF0YSRMeSksCiAgICAgICJDbHVzdGVyIiA9ICBhcy5jaGFyYWN0ZXIob2JqW1siY2x1c3RlciJdXSksCiAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKICAgIG9iaiA8LSBvYmpbWyJmcGNhIl1dCiAgfQogIGlmKGRlck9wdG5zJHAgPiAwKSB7CiAgICBzZWxlY3RlZEsgPC0gZmRhcGFjZTo6U2VsZWN0SyhvYmopJEsKICAgIGlmKCFpcy5maW5pdGUoc2VsZWN0ZWRLKSkgc2VsZWN0ZWRLIDwtIG5jb2wob2JqJHhpRXN0KQogIH0gIAogIGZpdCA8LSBmZGFwYWNlOjo6Zml0dGVkLkZQQ0Eob2JqLCBLID0gc2VsZWN0ZWRLLCBkZXJPcHRucyA9IGRlck9wdG5zKQogIHJvd25hbWVzKGZpdCkgPC0gbmFtZXMob2JqJGlucHV0RGF0YSRMeSkKICBjb2xuYW1lcyhmaXQpIDwtIG9iaiR3b3JrR3JpZAogIGZpdCA8LSByZXNoYXBlMjo6bWVsdChmaXQsIHZhcm5hbWVzID0gYygiUmVwbGljYXRlX0lEIiwgInRpbWUiKSkgJT4lCiAgICBtdXRhdGUoUmVwbGljYXRlX0lEID0gYXMuY2hhcmFjdGVyKFJlcGxpY2F0ZV9JRCkpCiAgaWYoIWlzLm51bGwoY2x1c3RfZGYpKXsKICAgIGZpdCA8LSBzdXBwcmVzc01lc3NhZ2VzKGZpdCAgJT4lIGxlZnRfam9pbihjbHVzdF9kZikpCiAgfQogIHJldHVybihmaXQpCn0KCgpmaXRfZGlzdF90b19iYXNlbGluZSA8LSBmdW5jdGlvbigKICBkaXN0X3RvX2Jhc2VsaW5lLCB0aW1lX2NvbHVtbj0iUmVsRGF5IiwgCiAgdmFsdWVfY29sdW1uID0gImRpc3RfdG9fYmFzZWxpbmUiLCByZXBsaWNhdGVfY29sdW1uID0gIlN1YmplY3QiKSAKewogIG5HcmlkIDwtIGxlbmd0aCgKICAgIHNlcShtaW4oZGlzdF90b19iYXNlbGluZVtbdGltZV9jb2x1bW5dXSksCiAgICAgICAgbWF4KGRpc3RfdG9fYmFzZWxpbmVbW3RpbWVfY29sdW1uXV0pKSkKICBmcGNhX3JlcyA8LSBmaXRfZmRhcGNhKAogICAgZGlzdF90b19iYXNlbGluZSwgdGltZV9jb2x1bW4sIHZhbHVlX2NvbHVtbiwgcmVwbGljYXRlX2NvbHVtbiwKICAgIGNsdXN0ZXIgPSBGQUxTRSwgZmlsdGVyID0gRkFMU0UsIGZwY2Ffb3B0bnMgPSBsaXN0KG5SZWdHcmlkID0gbkdyaWQpKQogIAogIGZpdHRlZF9tZWFuIDwtIGRhdGEuZnJhbWUodGltZSA9IGZwY2FfcmVzJHdvcmtHcmlkLCB2YWx1ZSA9IGZwY2FfcmVzJG11KQogIGZpdHRlZF9yZXNwb25zZSA8LSBmaXR0ZWRfdmFsdWVzX2ZwY2EoZnBjYV9yZXMpICU+JQogICAgbXV0YXRlKFN1YmplY3QgPSBSZXBsaWNhdGVfSUQpICU+JQogICAgbGVmdF9qb2luKAogICAgICBmaXR0ZWRfdmFsdWVzX2ZwY2EoZnBjYV9yZXMsIGRlck9wdG5zID0gbGlzdChwID0gMSkpICU+JQogICAgICAgIG11dGF0ZShTdWJqZWN0ID0gUmVwbGljYXRlX0lEKSAlPiUKICAgICAgICByZW5hbWUoImRlcml2IiA9IHZhbHVlKQogICAgKQogIHJldHVybihsaXN0KHJlcyA9IGZwY2FfcmVzLCBtZWFuID0gZml0dGVkX21lYW4sIGZpdHRlZCA9IGZpdHRlZF9yZXNwb25zZSkpCn0KYGBgCgoKYGBge3J9CiMgdGhpcyBpcyBiZWNhdXNlIHNvbWUgc3ViamVjdHMgaGF2ZSBtdWx0aXBsZSBzYW1wbGVzIHRha2UgdGhlIHNhbWUgZGF5CmJyYXlfdG9fYmFzZWxpbmVfZmx0ciA8LSBicmF5X3RvX2Jhc2VsaW5lICU+JSAKICBncm91cF9ieShwZXJ0dXJiYXRpb24sIFN1YmplY3QsIEdyb3VwLCBJbnRlcnZhbCwgUmVsRGF5KSAlPiUKICBzdW1tYXJpc2UobiA9IG4oKSwgZGlzdF90b19iYXNlbGluZSA9IG1lYW4oZGlzdF90b19iYXNlbGluZSkpICU+JQogIHVuZ3JvdXAoKQoKYnJheV90b19iYXNlbGluZV9mbHRyICU+JSBmaWx0ZXIobiA+IDEpCgpgYGAKCiMjIEFudGliaW90aWNzCgoKYGBge3IgYnJheS1hYnh9CmJyYXlfdG9fYmFzZWxpbmVfZmx0ciAlPiUgCiAgZmlsdGVyKHBlcnR1cmJhdGlvbiA9PSAiQWJ4IikgJT4lCiAgZmlsdGVyKFJlbERheSA+PSAtNTAsIFJlbERheSA8PSA2MCkgJT4lCiAgbXV0YXRlKEludGVydmFsID0gZmFjdG9yKEludGVydmFsLCBsZXZlbCA9IG5hbWVzKGFieF9pbnR2X2NvbHMpKSkgJT4lCiAgZ2dwbG90KAogICAgYWVzKHggPSBSZWxEYXksIHkgPSBkaXN0X3RvX2Jhc2VsaW5lLCAKICAgICAgICBncm91cCA9IFN1YmplY3QsIGNvbG9yID0gSW50ZXJ2YWwpKSArCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IFN1YmplY3QpLCBhbHBoYSA9IDAuNywgbHdkID0gMC41KSArIAogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUsIHNpemUgPSAxLjIpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGFieF9pbnR2X2NvbHMpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsgCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemU9MykpKSArCiAgeGxhYigiRGF5cyBmcm9tIGluaXRpYWwgYW50aWJpb3RpYyBkb3NlIikgKwogIHlsYWIoIkJyYXktQ3VydGlzIGRpc3RhbmNlIHRvIDcgcHJlLWFudGliaW90aWMgc2FtcGxlcyIpIApgYGAKCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpmcGNhLmJyYXkuYWJ4IDwtIGZpdF9kaXN0X3RvX2Jhc2VsaW5lKAogIGJyYXlfdG9fYmFzZWxpbmVfZmx0ciAlPiUgZmlsdGVyKHBlcnR1cmJhdGlvbiA9PSAiQWJ4IiwgUmVsRGF5ID49IC01MCwgUmVsRGF5IDw9IDYwKSkKCnNhdmUobGlzdCA9IGMoImZwY2EuYnJheS5hYngiKSwgZmlsZSA9ICJvdXRwdXQvZnBjYV9yZXMucmRhIikKYGBgCgpgYGB7ciBmcGNhLWJyYXktYWJ4LCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9Ni41fQoocEFieCA8LSBicmF5X3RvX2Jhc2VsaW5lX2ZsdHIgJT4lIAogIGZpbHRlcihwZXJ0dXJiYXRpb24gPT0gIkFieCIsIFJlbERheSA+PSAtNTAsIFJlbERheSA8PSA2MCkgJT4lCmdncGxvdChhZXMoeCA9IFJlbERheSwgeSA9IGRpc3RfdG9fYmFzZWxpbmUpKSArCiAgZ2VvbV9saW5lKAogICAgZGF0YSA9IGZwY2EuYnJheS5hYnhbWyJmaXR0ZWQiXV0sCiAgICBhZXMoZ3JvdXAgPSBTdWJqZWN0LCB4ID0gdGltZSwgeSA9IHZhbHVlKSwKICAgIGFscGhhID0gMC4zLCBzaXplID0gMC43LCBjb2xvciA9ICJncmV5MzAiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbHdkID0gMSwgY29sb3IgPSAib3JhbmdlIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDQsIGx3ZCA9IDEsIGNvbG9yID0gIm9yYW5nZSIpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IEludGVydmFsKSwgc2l6ZSA9IDEuNSwgYWxwaGEgPSAwLjcpICsKICBnZW9tX2xpbmUoCiAgICBkYXRhID0gZnBjYS5icmF5LmFieFtbIm1lYW4iXV0sIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlKSwKICAgIGNvbG9yID0gIm5hdnkiLCBzaXplID0gMikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBhYnhfaW50dl9jb2xzLCBuYW1lID0gIkludGVydmFsIikgKwogIHNjYWxlX3hfY29udGludW91cygKICAgIG5hbWUgPSAiRGF5cyBmcm9tIGluaXRpYWwgYW50aWJpb3RpYyBkb3NlIiwKICAgIGxpbWl0cyA9IGMoTkEsIE5BKSwgYnJlYWtzID0gc2VxKC01MCwgNjAsIDEwKSkgKwogIHNjYWxlX3lfY29udGludW91cygKICAgIG5hbWUgPSAiQnJheS1DdXJ0aXMgZGlzdGFuY2UgdG8gYmFzZWxpbmUiLCAKICAgIGxpbWl0cyA9IGMoMC4xLCAwLjg1KSwgYnJlYWtzID0gc2VxKDAuMSwgMC44MCwgMC4xKSkgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSkpCmBgYAoKCmBgYHtyIGZwY2EtZGVyaXYtYnJheS1hYngsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD02LjV9CmZwY2EuYnJheS5hYnhbWyJmaXR0ZWQiXV0gPC0gZnBjYS5icmF5LmFieFtbImZpdHRlZCJdXSAlPiUKICBtdXRhdGUoCiAgICBJbnRlcnZhbCA9IGlmZWxzZShmcGNhLmJyYXkuYWJ4W1siZml0dGVkIl1dJHRpbWUgPCAwICwgIlByZUFieCIsCiAgICAgICAgICAgICAgIGlmZWxzZShmcGNhLmJyYXkuYWJ4W1siZml0dGVkIl1dJHRpbWUgPj0gMCAmIGZwY2EuYnJheS5hYnhbWyJmaXR0ZWQiXV0kdGltZSA8PSA0LCAiTWlkQWJ4IiwKICAgICAgICAgICAgICAgICAgICAgICJQb3N0QWJ4IikpKQoKKHBBYnhEZXJpdiA8LSAgZnBjYS5icmF5LmFieFtbImZpdHRlZCJdXSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBSZWxEYXkpKSArCiAgZ2VvbV9saW5lKAogICAgYWVzKGdyb3VwID0gU3ViamVjdCwgeCA9IHRpbWUsIHkgPSBkZXJpdiwgY29sb3IgPSBJbnRlcnZhbCksCiAgICBhbHBoYSA9IDAuNSwgc2l6ZSA9IDAuNykgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGx3ZCA9IDEsIGNvbG9yID0gIm9yYW5nZSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSA0LCBsd2QgPSAxLCBjb2xvciA9ICJvcmFuZ2UiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGFieF9pbnR2X2NvbHMsIG5hbWUgPSAiSW50ZXJ2YWwiKSArCiAgc2NhbGVfeF9jb250aW51b3VzKG5hbWUgPSAiIiwKICAgIGxpbWl0cyA9IGMoTkEsIE5BKSwgYnJlYWtzID0gc2VxKC01MCwgNjAsIDEwKSkgKwogIHlsYWIoIkRlcml2YXRpdmUiKSkKYGBgCgoKYGBge3IgZnBjYS1icmF5LWFieC1sYWJzLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9Ni41fQoocEFieExhYiA8LSBicmF5X3RvX2Jhc2VsaW5lX2ZsdHIgJT4lIAogIGZpbHRlcihwZXJ0dXJiYXRpb24gPT0gIkFieCIsIFJlbERheSA+PSAtNTAsIFJlbERheSA8PSA2MCkgJT4lCmdncGxvdChhZXMoeCA9IFJlbERheSwgeSA9IGRpc3RfdG9fYmFzZWxpbmUpKSArCiAgZ2VvbV9saW5lKAogICAgZGF0YSA9IGZwY2EuYnJheS5hYnhbWyJmaXR0ZWQiXV0sCiAgICBhZXMoZ3JvdXAgPSBTdWJqZWN0LCB4ID0gdGltZSwgeSA9IHZhbHVlKSwKICAgIGFscGhhID0gMC4zLCBzaXplID0gMC43ICkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGx3ZCA9IDEsIGNvbG9yID0gIm9yYW5nZSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSA0LCBsd2QgPSAxLCBjb2xvciA9ICJvcmFuZ2UiKSArCiAgZ2VvbV90ZXh0KAogICAgICBhZXMobGFiZWwgPSBTdWJqZWN0LCBjb2xvciA9IEludGVydmFsKSwgc2l6ZSA9IDQsIGFscGhhID0gMC43KSArCiAgZ2VvbV9saW5lKAogICAgZGF0YSA9IGZwY2EuYnJheS5hYnhbWyJtZWFuIl1dLCBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZSksCiAgICBjb2xvciA9ICJuYXZ5Iiwgc2l6ZSA9IDIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYWJ4X2ludHZfY29scywgbmFtZSA9ICJJbnRlcnZhbCIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoCiAgICBuYW1lID0gIkRheXMgZnJvbSBpbml0aWFsIGFudGliaW90aWMgZG9zZSIsCiAgICBsaW1pdHMgPSBjKE5BLCBOQSksIGJyZWFrcyA9IHNlcSgtNTAsIDYwLCAxMCkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoCiAgICBuYW1lID0gIkJyYXktQ3VydGlzIGRpc3RhbmNlIHRvIGJhc2VsaW5lIiwgCiAgICBsaW1pdHMgPSBjKDAuMSwgMC44NSksIGJyZWFrcyA9IHNlcSgwLjEsIDAuODAsIDAuMSkpICsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCkpKQoKICAjIGdlb21fcG9pbnQoCiAgIyAgICAgZGF0YSA9IGFieF9icmF5ICU+JSBmaWx0ZXIoUmVsRGF5ID4gU3RhYlRpbWUpLAogICMgICAgIGNvbG9yID0gIm9yYW5nZSIsIHNpemUgPSAyLjUpICsKYGBgCgpgYGB7ciBmcGNhLWJyYXktYWJ4LXZhbC1kZXJpdiwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTYuNX0KdnAgPSBncmlkOjp2aWV3cG9ydCh3aWR0aCA9IDAuMywgaGVpZ2h0ID0gMC4zMiwgeCA9IDAuMDcsIHkgPTAuOTUsIGp1c3QgPSBjKCJsZWZ0IiwgInRvcCIpKQpwcmludChwQWJ4KQpwcmludChwQWJ4RGVyaXYgKyB0aGVtZV9idyhiYXNlX3NpemUgPSAxMCkgKyB0aGVtZV9zdWJwbG90LCB2cCA9IHZwKQpgYGAKCgoKIyMgRGlldAoKCgpgYGB7cn0KYnJheV90b19iYXNlbGluZV9mbHRyICU+JSAKICBmaWx0ZXIocGVydHVyYmF0aW9uID09ICJEaWV0IiwgUmVsRGF5ID49IC0zMCwgUmVsRGF5IDw9IDMwKSAlPiUKICBtdXRhdGUoSW50ZXJ2YWwgPSBmYWN0b3IoSW50ZXJ2YWwsIGxldmVsID0gbmFtZXMoZGlldF9pbnR2X2NvbHMpKSkgJT4lCiAgZ2dwbG90KAogICAgYWVzKHggPSBSZWxEYXksIHkgPSBkaXN0X3RvX2Jhc2VsaW5lLCAKICAgICAgICBncm91cCA9IFN1YmplY3QsIGNvbG9yID0gSW50ZXJ2YWwpKSArCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IFN1YmplY3QpLCBhbHBoYSA9IDAuNywgbHdkID0gMC41KSArIAogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUsIHNpemUgPSAxLjIpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGRpZXRfaW50dl9jb2xzKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArIAogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTMpKSkgKwogIHhsYWIoIkRheXMgZnJvbSBkaWV0IGluaXRpYXRpb24iKSArCiAgeWxhYigiQnJheS1DdXJ0aXMgZGlzdGFuY2UgdG8gNyBwcmUtZGlldCBzYW1wbGVzIikgCmBgYAoKCmBgYHtyLCBldmFsID0gRkFMU0V9CmZwY2EuYnJheS5kaWV0MzAgPC0gZml0X2Rpc3RfdG9fYmFzZWxpbmUoCiAgYnJheV90b19iYXNlbGluZV9mbHRyICU+JSBmaWx0ZXIocGVydHVyYmF0aW9uID09ICJEaWV0IiwgUmVsRGF5ID49IC0zMCwgUmVsRGF5IDw9IDMwKSkKCnNhdmUobGlzdCA9IGMoImZwY2EuYnJheS5hYngiLCAiZnBjYS5icmF5LmRpZXQiLCAiZnBjYS5icmF5LmRpZXQzMCIpLCBmaWxlID0gIm91dHB1dC9mcGNhX3Jlcy5yZGEiKQpgYGAKCmBgYHtyIGZwY2EtYnJheS1kaWV0LCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9Ni41fQoocERpZXQgPC0gYnJheV90b19iYXNlbGluZV9mbHRyICU+JSAKICBmaWx0ZXIocGVydHVyYmF0aW9uID09ICJEaWV0IiwgUmVsRGF5ID49IC0zMCwgUmVsRGF5IDw9IDMwKSAlPiUKZ2dwbG90KGFlcyh4ID0gUmVsRGF5LCB5ID0gZGlzdF90b19iYXNlbGluZSkpICsKICBnZW9tX2xpbmUoCiAgICBkYXRhID0gZnBjYS5icmF5LmRpZXQzMFtbImZpdHRlZCJdXSwKICAgIGFlcyhncm91cCA9IFN1YmplY3QsIHggPSB0aW1lLCB5ID0gdmFsdWUpLAogICAgYWxwaGEgPSAwLjMsIHNpemUgPSAwLjcsIGNvbG9yID0gImdyZXkzMCIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsd2QgPSAxLCBjb2xvciA9ICJvcmFuZ2UiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gNCwgbHdkID0gMSwgY29sb3IgPSAib3JhbmdlIikgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gSW50ZXJ2YWwpLCBzaXplID0gMS41LCBhbHBoYSA9IDAuNykgKwogIGdlb21fbGluZSgKICAgIGRhdGEgPSBmcGNhLmJyYXkuZGlldDMwW1sibWVhbiJdXSwgYWVzKHggPSB0aW1lLCB5ID0gdmFsdWUpLAogICAgY29sb3IgPSAibmF2eSIsIHNpemUgPSAyKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGRpZXRfaW50dl9jb2xzLCBuYW1lID0gIkludGVydmFsIikgKwogIHNjYWxlX3hfY29udGludW91cygKICAgIG5hbWUgPSAiRGF5cyBmcm9tIGluaXRpYWwgYW50aWJpb3RpYyBkb3NlIiwKICAgIGxpbWl0cyA9IGMoTkEsIE5BKSwgYnJlYWtzID0gc2VxKC01MCwgNjAsIDEwKSkgKwogIHNjYWxlX3lfY29udGludW91cygKICAgIG5hbWUgPSAiQnJheS1DdXJ0aXMgZGlzdGFuY2UgdG8gYmFzZWxpbmUiLCAKICAgIGxpbWl0cyA9IGMoTkEsIE5BKSwgYnJlYWtzID0gc2VxKDAuMSwgMC44MCwgMC4xKSkgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSkpIApgYGAKCgpgYGB7ciBmcGNhLWRlcml2LWJyYXktZGlldCwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTYuNX0KZnBjYS5icmF5LmRpZXQzMFtbImZpdHRlZCJdXSA8LSBmcGNhLmJyYXkuZGlldDMwW1siZml0dGVkIl1dICU+JQogIG11dGF0ZSgKICAgIEludGVydmFsID0gaWZlbHNlKGZwY2EuYnJheS5kaWV0MzBbWyJmaXR0ZWQiXV0kdGltZSA8IDAgLCAiUHJlRGlldCIsCiAgICAgICAgICAgICAgIGlmZWxzZShmcGNhLmJyYXkuZGlldDMwW1siZml0dGVkIl1dJHRpbWUgPj0gMCAmIGZwY2EuYnJheS5kaWV0MzBbWyJmaXR0ZWQiXV0kdGltZSA8PSA0LCAiTWlkRGlldCIsCiAgICAgICAgICAgICAgICAgICAgICAiUG9zdERpZXQiKSkpCgoocERpZXREZXJpdiA8LSAgZnBjYS5icmF5LmRpZXQzMFtbImZpdHRlZCJdXSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBSZWxEYXkpKSArCiAgZ2VvbV9saW5lKAogICAgYWVzKGdyb3VwID0gU3ViamVjdCwgeCA9IHRpbWUsIHkgPSBkZXJpdiwgY29sb3IgPSBJbnRlcnZhbCksCiAgICBhbHBoYSA9IDAuNSwgc2l6ZSA9IDAuNykgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGx3ZCA9IDEsIGNvbG9yID0gIm9yYW5nZSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSA0LCBsd2QgPSAxLCBjb2xvciA9ICJvcmFuZ2UiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGRpZXRfaW50dl9jb2xzLCBuYW1lID0gIkludGVydmFsIikgKwogIHNjYWxlX3hfY29udGludW91cyhuYW1lID0gIiIsCiAgICBsaW1pdHMgPSBjKE5BLCBOQSksIGJyZWFrcyA9IHNlcSgtNTAsIDYwLCAxMCkpICsKICB5bGFiKCJEZXJpdmF0aXZlIikpCmBgYAoKCmBgYHtyIGZwY2EtYnJheS1kaWV0LWxhYnMsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD02LjV9CihwRGlldExhYiA8LSBicmF5X3RvX2Jhc2VsaW5lX2ZsdHIgJT4lIAogIGZpbHRlcihwZXJ0dXJiYXRpb24gPT0gIkRpZXQiLCBSZWxEYXkgPj0gLTUwLCBSZWxEYXkgPD0gNjApICU+JQpnZ3Bsb3QoYWVzKHggPSBSZWxEYXksIHkgPSBkaXN0X3RvX2Jhc2VsaW5lKSkgKwogIGdlb21fbGluZSgKICAgIGRhdGEgPSBmcGNhLmJyYXkuZGlldFtbImZpdHRlZCJdXSwKICAgIGFlcyhncm91cCA9IFN1YmplY3QsIHggPSB0aW1lLCB5ID0gdmFsdWUpLAogICAgYWxwaGEgPSAwLjMsIHNpemUgPSAwLjcgKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbHdkID0gMSwgY29sb3IgPSAib3JhbmdlIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDQsIGx3ZCA9IDEsIGNvbG9yID0gIm9yYW5nZSIpICsKICBnZW9tX3RleHQoCiAgICAgIGFlcyhsYWJlbCA9IFN1YmplY3QsIGNvbG9yID0gSW50ZXJ2YWwpLCBzaXplID0gNCwgYWxwaGEgPSAwLjcpICsKICBnZW9tX2xpbmUoCiAgICBkYXRhID0gZnBjYS5icmF5LmRpZXRbWyJtZWFuIl1dLCBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZSksCiAgICBjb2xvciA9ICJuYXZ5Iiwgc2l6ZSA9IDIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gZGlldF9pbnR2X2NvbHMsIG5hbWUgPSAiSW50ZXJ2YWwiKSArCiAgc2NhbGVfeF9jb250aW51b3VzKAogICAgbmFtZSA9ICJEYXlzIGZyb20gaW5pdGlhbCBhbnRpYmlvdGljIGRvc2UiLAogICAgbGltaXRzID0gYyhOQSwgTkEpLCBicmVha3MgPSBzZXEoLTUwLCA2MCwgMTApKSArCiAgc2NhbGVfeV9jb250aW51b3VzKAogICAgbmFtZSA9ICJCcmF5LUN1cnRpcyBkaXN0YW5jZSB0byBiYXNlbGluZSIsIAogICAgbGltaXRzID0gYygwLjEsIDAuODUpLCBicmVha3MgPSBzZXEoMC4xLCAwLjgwLCAwLjEpKSArCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApKSkKCmBgYAoKCmBgYHtyIGZwY2EtYnJheS1kaWV0LXZhbC1kZXJpdiwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTYuNX0KdnAgPSBncmlkOjp2aWV3cG9ydCh3aWR0aCA9IDAuMywgaGVpZ2h0ID0gMC4zMiwgeCA9IDAuMDcsIHkgPTAuOTUsIGp1c3QgPSBjKCJsZWZ0IiwgInRvcCIpKQpwcmludChwRGlldCkKcHJpbnQocERpZXREZXJpdiArIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDEwKSArIHRoZW1lX3N1YnBsb3QsIHZwID0gdnApCmBgYAoKIyMgQ29sb24gY2xlYW5vdXQKCgoKYGBge3IgYnJheS1jY30KYnJheV90b19iYXNlbGluZV9mbHRyICU+JSAKICBmaWx0ZXIocGVydHVyYmF0aW9uID09ICJDQyIsIFJlbERheSA+PSAtNTAsIFJlbERheSA8PSA1MCkgJT4lCiAgbXV0YXRlKEludGVydmFsID0gZmFjdG9yKEludGVydmFsLCBsZXZlbCA9IG5hbWVzKGNjX2ludHZfY29scykpKSAlPiUKICBnZ3Bsb3QoCiAgICBhZXMoeCA9IFJlbERheSwgeSA9IGRpc3RfdG9fYmFzZWxpbmUsIAogICAgICAgIGdyb3VwID0gU3ViamVjdCwgY29sb3IgPSBJbnRlcnZhbCkpICsKICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gU3ViamVjdCksIGFscGhhID0gMC43LCBsd2QgPSAwLjUpICsgCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNSwgc2l6ZSA9IDEuMikgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2NfaW50dl9jb2xzKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArIAogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTMpKSkgKwogIHhsYWIoIkRheXMgZnJvbSBkaWV0IGluaXRpYXRpb24iKSArCiAgeWxhYigiQnJheS1DdXJ0aXMgZGlzdGFuY2UgdG8gNyBwcmUtZGlldCBzYW1wbGVzIikgCmBgYAoKCmBgYHtyfQpmcGNhLmJyYXkuY2MzMCA8LSBmaXRfZGlzdF90b19iYXNlbGluZSgKICBicmF5X3RvX2Jhc2VsaW5lX2ZsdHIgJT4lIAogICAgZmlsdGVyKHBlcnR1cmJhdGlvbiA9PSAiQ0MiLCBSZWxEYXkgPj0gLTMwLCBSZWxEYXkgPD0gMzApICU+JQogICAgYXJyYW5nZShTdWJqZWN0LCBSZWxEYXkpKQoKc2F2ZShsaXN0ID0gYygiZnBjYS5icmF5LmFieCIsICJmcGNhLmJyYXkuZGlldCIsImZwY2EuYnJheS5kaWV0MzAiLCAKICAgICAgICAgICAgICAiZnBjYS5icmF5LmNjIiwgImZwY2EuYnJheS5jYzMwIiksIAogICAgIGZpbGUgPSAib3V0cHV0L2ZwY2FfcmVzLnJkYSIpCmBgYAoKYGBge3IgZnBjYS1icmF5LWNjLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9Ni41fQoocENDIDwtIGJyYXlfdG9fYmFzZWxpbmVfZmx0ciAlPiUgCiAgZmlsdGVyKHBlcnR1cmJhdGlvbiA9PSAiQ0MiLCBSZWxEYXkgPj0gLTMwLCBSZWxEYXkgPD0gMzApICU+JQpnZ3Bsb3QoYWVzKHggPSBSZWxEYXksIHkgPSBkaXN0X3RvX2Jhc2VsaW5lKSkgKwogIGdlb21fbGluZSgKICAgIGRhdGEgPSBmcGNhLmJyYXkuY2MzMFtbImZpdHRlZCJdXSwKICAgIGFlcyhncm91cCA9IFN1YmplY3QsIHggPSB0aW1lLCB5ID0gdmFsdWUpLAogICAgYWxwaGEgPSAwLjMsIHNpemUgPSAwLjcsIGNvbG9yID0gImdyZXkzMCIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsd2QgPSAxLCBjb2xvciA9ICJvcmFuZ2UiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gNCwgbHdkID0gMSwgY29sb3IgPSAib3JhbmdlIikgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gSW50ZXJ2YWwpLCBzaXplID0gMS41LCBhbHBoYSA9IDAuNykgKwogIGdlb21fbGluZSgKICAgIGRhdGEgPSBmcGNhLmJyYXkuY2MzMFtbIm1lYW4iXV0sIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlKSwKICAgIGNvbG9yID0gIm5hdnkiLCBzaXplID0gMikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjY19pbnR2X2NvbHMsIG5hbWUgPSAiSW50ZXJ2YWwiKSArCiAgc2NhbGVfeF9jb250aW51b3VzKAogICAgbmFtZSA9ICJEYXlzIGZyb20gaW5pdGlhbCBhbnRpYmlvdGljIGRvc2UiLAogICAgbGltaXRzID0gYyhOQSwgTkEpLCBicmVha3MgPSBzZXEoLTUwLCA2MCwgMTApKSArCiAgc2NhbGVfeV9jb250aW51b3VzKAogICAgbmFtZSA9ICJCcmF5LUN1cnRpcyBkaXN0YW5jZSB0byBiYXNlbGluZSIsIAogICAgbGltaXRzID0gYyhOQSwgTkEpLCBicmVha3MgPSBzZXEoMC4xLCAwLjgwLCAwLjEpKSArCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApKSkgCmBgYAoKCmBgYHtyIGZwY2EtZGVyaXYtYnJheS1jYywgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTYuNX0KZnBjYS5icmF5LmNjMzBbWyJmaXR0ZWQiXV0gPC0gZnBjYS5icmF5LmNjMzBbWyJmaXR0ZWQiXV0gJT4lCiAgbXV0YXRlKEludGVydmFsID0gaWZlbHNlKGZwY2EuYnJheS5jYzMwW1siZml0dGVkIl1dJHRpbWUgPCAwICwgIlByZUNDIiwiUG9zdENDIikpCgoocENDRGVyaXYgPC0gIGZwY2EuYnJheS5jYzMwW1siZml0dGVkIl1dICU+JQogIGdncGxvdChhZXMoeCA9IFJlbERheSkpICsKICBnZW9tX2xpbmUoCiAgICBhZXMoZ3JvdXAgPSBTdWJqZWN0LCB4ID0gdGltZSwgeSA9IGRlcml2LCBjb2xvciA9IEludGVydmFsKSwKICAgIGFscGhhID0gMC41LCBzaXplID0gMC43KSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbHdkID0gMSwgY29sb3IgPSAib3JhbmdlIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDQsIGx3ZCA9IDEsIGNvbG9yID0gIm9yYW5nZSIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2NfaW50dl9jb2xzLCBuYW1lID0gIkludGVydmFsIikgKwogIHNjYWxlX3hfY29udGludW91cyhuYW1lID0gIiIsCiAgICBsaW1pdHMgPSBjKE5BLCBOQSksIGJyZWFrcyA9IHNlcSgtNTAsIDYwLCAxMCkpICsKICB5bGFiKCJEZXJpdmF0aXZlIikpCmBgYAoKCmBgYHtyIGZwY2EtYnJheS1jYy1sYWJzLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9Ni41fQoocENDTGFiIDwtIGJyYXlfdG9fYmFzZWxpbmVfZmx0ciAlPiUgCiAgZmlsdGVyKHBlcnR1cmJhdGlvbiA9PSAiQ0MiLCBSZWxEYXkgPj0gLTUwLCBSZWxEYXkgPD0gNTApICU+JQpnZ3Bsb3QoYWVzKHggPSBSZWxEYXksIHkgPSBkaXN0X3RvX2Jhc2VsaW5lKSkgKwogIGdlb21fbGluZSgKICAgIGRhdGEgPSBmcGNhLmJyYXkuY2NbWyJmaXR0ZWQiXV0sCiAgICBhZXMoZ3JvdXAgPSBTdWJqZWN0LCB4ID0gdGltZSwgeSA9IHZhbHVlKSwKICAgIGFscGhhID0gMC4zLCBzaXplID0gMC43ICkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGx3ZCA9IDEsIGNvbG9yID0gIm9yYW5nZSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSA0LCBsd2QgPSAxLCBjb2xvciA9ICJvcmFuZ2UiKSArCiAgZ2VvbV90ZXh0KAogICAgICBhZXMobGFiZWwgPSBTdWJqZWN0LCBjb2xvciA9IEludGVydmFsKSwgc2l6ZSA9IDQsIGFscGhhID0gMC43KSArCiAgZ2VvbV9saW5lKAogICAgZGF0YSA9IGZwY2EuYnJheS5jY1tbIm1lYW4iXV0sIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlKSwKICAgIGNvbG9yID0gIm5hdnkiLCBzaXplID0gMikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjY19pbnR2X2NvbHMsIG5hbWUgPSAiSW50ZXJ2YWwiKSArCiAgc2NhbGVfeF9jb250aW51b3VzKAogICAgbmFtZSA9ICJEYXlzIGZyb20gaW5pdGlhbCBhbnRpYmlvdGljIGRvc2UiLAogICAgbGltaXRzID0gYyhOQSwgTkEpLCBicmVha3MgPSBzZXEoLTUwLCA2MCwgMTApKSArCiAgc2NhbGVfeV9jb250aW51b3VzKAogICAgbmFtZSA9ICJCcmF5LUN1cnRpcyBkaXN0YW5jZSB0byBiYXNlbGluZSIsIAogICAgbGltaXRzID0gYygwLjEsIDAuODUpLCBicmVha3MgPSBzZXEoMC4xLCAwLjgwLCAwLjEpKSArCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApKSkKCmBgYAoKCmBgYHtyIGZwY2EtYnJheS1jYy12YWwtZGVyaXYsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD02LjV9CnZwID0gZ3JpZDo6dmlld3BvcnQod2lkdGggPSAwLjMsIGhlaWdodCA9IDAuMzIsIHggPSAwLjA3LCB5ID0wLjk1LCBqdXN0ID0gYygibGVmdCIsICJ0b3AiKSkKcHJpbnQocENDKQpwcmludChwQ0NEZXJpdiArIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDEwKSArIHRoZW1lX3N1YnBsb3QsIHZwID0gdnApCmBgYAoKYGBge3J9CnNlc3Npb25JbmZvKCkKYGBgCgo=